

package com.seed.marketed.common.logtrack.intercept;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.seed.marketed.common.logtrack.constants.LogConstants;
import com.seed.marketed.common.utils.ServletUtils;
import com.seed.marketed.common.utils.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.core.io.InputStreamSource;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.support.StandardMultipartHttpServletRequest;

import com.alibaba.fastjson.JSONObject;



@Component
@Aspect
public class ControllerLogIntercept {
	
	private static final Logger logger = LoggerFactory.getLogger(ControllerLogIntercept.class);
	private ThreadLocal<Long> threadLocal = new ThreadLocal<>();



	@Pointcut("execution(public * com.seed.marketed.*.*.controller..*.*(..))")
	public void cutController(){

	}

	@Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
	public void cutRequestMapping(){

	}

	@Pointcut("@annotation(org.springframework.web.bind.annotation.GetMapping)")
	public void cutGetMapping() {
	}

	@Pointcut("@annotation(org.springframework.web.bind.annotation.PostMapping)")
	public void cutPostMapping() {
	}

	@Pointcut("cutController() || cutRequestMapping() || cutGetMapping() || cutPostMapping()") // 切入点表达式
	 public void pointcut() {
		
	 }
	
	@Before(value = "pointcut()")
	public void before(JoinPoint joinPoint) {
		MDC.put(LogConstants.TRACE_ID, UUID.randomUUID().toString().replace("-", ""));
		// 获取执行的方法名称
		String className = joinPoint.getTarget().getClass().getSimpleName();
		String methodName = joinPoint.getSignature().getName();
		Object[] args = joinPoint.getArgs();
		StringBuilder params = new StringBuilder("参数====>" + className +"."+ methodName+"=>");
		//获取请求参数集合并进行遍历拼接
		for (Object object : args) {
			if(object instanceof HttpServletRequest || object instanceof HttpServletResponse) {
				continue;
			}

			if(object instanceof InputStreamSource) {
				continue;
			}

			if(object instanceof StandardMultipartHttpServletRequest) {
				continue;
			}

			try {
				params.append(JSONObject.toJSONString(object)+",");
			} catch (Exception e) {
				logger.info("json化参数异常");
			}

		}
		HttpServletRequest request = ServletUtils.getRequest();
		params.append("{url:"+request.getRequestURI()+"}");
		params.append("{channelCode:"+request.getHeader("channelCode")+"}");
		params.append("{token:"+ request.getHeader("token") +"}");

		threadLocal.set(System.currentTimeMillis());
		//打印请求参数参数
		logger.info(params.toString());
	}
	
	@AfterReturning(pointcut="pointcut()",returning="returnValue")
	public void afterHandle(JoinPoint point,Object returnValue){
		logger.info("返回====>{}  耗时====>{}",JSONObject.toJSONString(returnValue) , (System.currentTimeMillis() - threadLocal.get())+"ms" );
		threadLocal.remove();
		MDC.remove(LogConstants.TRACE_ID);
	}
	
	 @AfterThrowing(pointcut="pointcut()",throwing="e")
	public void afterThrowable(JoinPoint joinPoint,Throwable e){
		logger.info(StringUtils.buildAlarmMsg(null,null));
		logger.error("系统异常====>{}",getExceptionStack(e));
		threadLocal.remove();
		MDC.remove(LogConstants.TRACE_ID);
	}

	private static String getExceptionStack(Throwable throwable) {
		try(StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw)){
			throwable.printStackTrace(pw);
			pw.flush();
			sw.flush();
			return sw.toString();
		}catch (Exception ignored){
			logger.info("获取异常堆栈异常",ignored);
			return "获取堆栈异常";
		}
	}
}
